package edu.ubbcs.rs.web.view;

import com.vaadin.cdi.CDIView;
import com.vaadin.data.Property;
import com.vaadin.data.fieldgroup.BeanFieldGroup;
import com.vaadin.data.util.BeanItem;
import com.vaadin.event.FieldEvents;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.Button;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.DateField;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Label;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import edu.ubbcs.rs.backend.model.Reservation;
import edu.ubbcs.rs.backend.model.ReservationEvent;
import edu.ubbcs.rs.backend.model.Role;
import edu.ubbcs.rs.backend.model.User;
import edu.ubbcs.rs.backend.model.room.Room;
import edu.ubbcs.rs.backend.model.table.Table;
import edu.ubbcs.rs.backend.service.ReservationService;
import edu.ubbcs.rs.backend.service.UserService;
import edu.ubbcs.rs.backend.service.filter.manager.FilterService;
import edu.ubbcs.rs.web.util.ApplicationContext;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import javax.annotation.PostConstruct;
import javax.inject.Inject;

/**
 *
 * @author Merli András-Bertalan
 */
@CDIView(value = StartView.NAME)
public class StartView extends VerticalLayout implements View {

    public static final String NAME = "StartView";
    @Inject
    private FilterService filterService;
    @Inject
    private ReservationService reservationService;
    @Inject
    private UserService userService;
    private Panel searchPanel;
    private Panel reservationPanel;
    private AbsoluteLayout roomLayout;
    private HorizontalSplitPanel splitPanel;
    private User currentUser;
    private Room currentRoom;
    private Role currentRole;
    private BeanFieldGroup reservationBeanFieldGroup;
    private List<Integer> hourList;
    private List<Role> roleList;
    private List<ReservationEvent> eventList;
    private ComboBox event;
    private TextField nameTextField;

    public StartView() {
    }

    @PostConstruct
    public void startViewPostConstruct() {
//        tableRepository.insert(new SimpleTable(100, 100, 20, 20));
//        tableRepository.insert(new SimpleTable(100, 100, 150, 150));
//        tableRepository.insert(new SimpleTable(100, 100, 20, 270));

        hourList = new ArrayList<>(11);
//        hourList.add(null);
        for (int i = 10; i < 20; i++) {
            hourList.add(i);
        }
        eventList = new ArrayList<>(2);
//        eventList.add(null);
        eventList.add(ReservationEvent.WEDDING);
        roleList = new ArrayList<>(2);
        roleList.add(Role.ADMIN);
        roleList.add(Role.GUEST);

//        setSizeFull();
        currentUser = ApplicationContext.getCurrentUser();
        currentRole = currentUser.getRole();
        splitPanel = new HorizontalSplitPanel();
        Label label = new Label("Hello, " + currentUser.getName() + "!");
        initReservationPanel();
        initRoomLayout();
        initSearchPanel();
        splitPanel.setFirstComponent(roomLayout);
        addComponent(label);
        addComponent(searchPanel);
        addComponent(splitPanel);
    }

    @Override
    public void enter(ViewChangeEvent event) {
        filterService.eventChanged(null);
        filterService.hourChanged(null);
        filterService.reserverNameChanged(null);
        filterService.dateChanged(new Date());
        updateRoomLayout(filterService.filter(currentRole));
    }

    private void initReservationPanel() {
        reservationPanel = new Panel();
        reservationPanel.setSizeUndefined();
        reservationPanel.addStyleName("title");
        reservationPanel.setCaption("Reservation");
    }

    private void initRoomLayout() {
        roomLayout = new AbsoluteLayout();
        roomLayout.setWidth("400");
        roomLayout.setHeight("300");
    }

    private void updateRoomLayout(final List<Room> rooms) {
        roomLayout.removeAllComponents();
        final Button previousRoomButton = new Button("<");
        final Button nextRoomButton = new Button(">");
        final Label countLabel = new Label("0/0");
        final Label dateHourLabel = new Label("");
        final HorizontalLayout hl = new HorizontalLayout(previousRoomButton, nextRoomButton, countLabel, dateHourLabel);
        hl.setSpacing(true);
        roomLayout.addComponent(hl, "left: 10px; top: 10px;");

        final ListIterator<Room> iterator = rooms.listIterator();
        previousRoomButton.addClickListener(new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                currentRoom = iterator.previous();
                countLabel.setValue((rooms.indexOf(currentRoom) + 1) + "/" + rooms.size());
                dateHourLabel.setValue(new SimpleDateFormat("yyyy-MM-dd").format(currentRoom.getDate()) + " " + currentRoom.getHour() + "h");
                if (iterator.hasPrevious() && rooms.size() != 1) {
                    previousRoomButton.setVisible(true);
                } else {
                    previousRoomButton.setVisible(false);
                }
                if (iterator.hasNext() && rooms.size() != 1) {
                    nextRoomButton.setVisible(true);
                } else {
                    nextRoomButton.setVisible(false);
                }
                roomLayout.removeAllComponents();
                roomLayout.addComponent(hl, "left: 10px; top: 10px;");
                for (final Table table : currentRoom.getTables()) {
                    final NativeButton tableButton = new NativeButton();
                    tableButton.setData(table);
                    tableButton.setWidth(String.valueOf(table.getWeight()));
                    tableButton.setHeight(String.valueOf(table.getHeight()));
                    tableButton.addClickListener(new Button.ClickListener() {

                        @Override
                        public void buttonClick(Button.ClickEvent event) {
                            updateReservationPanel(tableButton);
                        }
                    });
                    if (!currentRoom.isReserved(table)) {
                        tableButton.addStyleName("green");
                    } else {
                        tableButton.addStyleName("gray");
                    }
                    roomLayout.addComponent(tableButton, "left: " + table.getX() + "px; bottom: " + table.getY() + "px;");
                }
                splitPanel.removeComponent(reservationPanel);
            }
        });
        nextRoomButton.addClickListener(new Button.ClickListener() {

            @Override
            public void buttonClick(Button.ClickEvent event) {
                currentRoom = iterator.next();
                countLabel.setValue((rooms.indexOf(currentRoom) + 1) + "/" + rooms.size());
                dateHourLabel.setValue(new SimpleDateFormat("yyyy-MM-dd").format(currentRoom.getDate()) + " " + currentRoom.getHour() + "h");
                if (iterator.hasPrevious() && rooms.size() != 1) {
                    previousRoomButton.setVisible(true);
                } else {
                    previousRoomButton.setVisible(false);
                }
                if (iterator.hasNext() && rooms.size() != 1) {
                    nextRoomButton.setVisible(true);
                } else {
                    nextRoomButton.setVisible(false);
                }
                roomLayout.removeAllComponents();
                roomLayout.addComponent(hl, "left: 10px; top: 10px;");
                for (final Table table : currentRoom.getTables()) {
                    final NativeButton tableButton = new NativeButton();
                    tableButton.setData(table);
                    tableButton.setWidth(String.valueOf(table.getWeight()));
                    tableButton.setHeight(String.valueOf(table.getHeight()));
                    tableButton.addClickListener(new Button.ClickListener() {

                        @Override
                        public void buttonClick(Button.ClickEvent event) {
                            updateReservationPanel(tableButton);
                        }
                    });
                    if (!currentRoom.isReserved(table)) {
                        tableButton.addStyleName("green");
                    } else {
                        tableButton.addStyleName("gray");
                    }
                    roomLayout.addComponent(tableButton, "left: " + table.getX() + "px; bottom: " + table.getY() + "px;");
                }
                splitPanel.removeComponent(reservationPanel);
            }
        });
        if (iterator.hasNext()) {
            nextRoomButton.click();
        }
    }

    private void updateReservationPanel(final NativeButton nativeButton) {
        final Table table = (Table) nativeButton.getData();
        boolean reserved2 = false;
        for (Reservation res : currentRoom.getReservations()) {
            System.out.println(res.getTable().getId() + " - " + table.getId());
            if (res.getTable().getId().equals(table.getId())) {
                reserved2 = true;
            }
        }
        System.out.println("RESERVED: " + reserved2 + " RESSIZE: " + currentRoom.getReservations().size());

        splitPanel.removeComponent(reservationPanel);

        Reservation reservation = null;
        boolean reserved = false;
        System.out.println("Update RP, currentRole: " + currentRole + " role: " + currentUser.getRole());
        if (Role.GUEST.equals(currentRole)) {
            System.out.println("reserved: " + currentRoom.isReserved(table) + " " + currentRoom.hashCode());
            if (currentRoom.isReserved(table)) {
                System.out.println("Update RP, currentRole==GUEST && reserved");
                return;
            }
            reservation = new Reservation(currentRoom.getDate(), currentRoom.getHour(), null, null, table, null);
            if (Role.ADMIN.equals(currentUser.getRole()) && nameTextField.getValue() != null) {
                System.out.println("Update RP, currentRole==GUEST && role==ADMIN && !reserved");
                User u = userService.getUserByUsername(nameTextField.getValue());
                System.out.println("user: " + u);
                if (u != null) {
                    reservation.setReserver(u);
                }
            } else {
                System.out.println("Update RP, currentRole==GUEST && role==GUEST && !reserved");
                reservation.setReserver(currentUser);
            }
        } else if (Role.ADMIN.equals(currentRole)) {
            System.out.println("reserved: " + currentRoom.isReserved(table) + " " + currentRoom.hashCode());
            if (currentRoom.isReserved(table)) {
                System.out.println("Update RP, currentRole, role==ADMIN && reserved");
                reserved = true;
                for (Reservation r : currentRoom.getReservations()) {
                    Table origTable = r.getTable();
                    List<Reservation> tableReservations = table.reserve(r);
                    r.setTable(origTable);
                    for (Reservation tableReservation : tableReservations) {
//                        if (currentRoom.getReservations().contains(tableReservation)) {
                        if (r.getTable().equals(tableReservation.getTable())) {
                            reservation = r;
                        }
                    }
                }
            } else {
                System.out.println("Update RP, currentrole, role==ADMIN && !reserved");
                reservation = new Reservation(currentRoom.getDate(), currentRoom.getHour(), null, null, table, null);
            }
        }

        reservationBeanFieldGroup = new BeanFieldGroup(Reservation.class);
        final BeanItem<Reservation> reservationItem = new BeanItem<>(reservation);
        reservationBeanFieldGroup.setItemDataSource(reservationItem);

        TextField reserverName = new TextField("Name: ");
        reserverName.setRequired(true);
        reserverName.setInvalidCommitted(true);
        reserverName.setNullRepresentation("");

        TextField reserverEmail = new TextField("Email: ");
        reserverEmail.setRequired(true);
        reserverEmail.setInvalidCommitted(true);
        reserverEmail.setNullRepresentation("");

        TextField reserverPhone = new TextField("Phone: ");
        reserverPhone.setRequired(true);
        reserverPhone.setInvalidCommitted(true);
        reserverPhone.setNullRepresentation("");

        TextField message = new TextField("Message: ");
        message.setInvalidCommitted(true);
        message.setNullRepresentation("");

        event = new ComboBox("Event: ", eventList);
        event.setNullSelectionAllowed(true);
        event.setInvalidCommitted(true);
        event.setImmediate(true);

        reservationBeanFieldGroup.bind(reserverName, "reserver.name");
        reservationBeanFieldGroup.bind(reserverEmail, "reserver.email");
        reservationBeanFieldGroup.bind(reserverPhone, "reserver.phone");
        reservationBeanFieldGroup.bind(message, "message");
        reservationBeanFieldGroup.bind(event, "reservationEvent");

        Button saveButton = new Button("Save");
        Button deleteButton = new Button("Delete");
        final HorizontalLayout buttons = new HorizontalLayout();
        if (!reserved) {
            buttons.addComponent(saveButton);
        } else {
            buttons.addComponent(deleteButton);
        }
        buttons.setSpacing(true);

        final FormLayout form = new FormLayout();
        form.setSpacing(true);
        form.addComponents(reserverName, reserverEmail, reserverPhone, message,
                event, buttons);

        saveButton.addClickListener(new Button.ClickListener() {

            @Override
            public void buttonClick(Button.ClickEvent e) {
                Reservation reservation = (Reservation) reservationBeanFieldGroup.getItemDataSource().getBean();
                if (event.getValue() != null) {
                    reservation.setReservationEvent((ReservationEvent) event.getValue());
                }
                reservationService.insert(reservation);
                currentRoom.reserve(reservation, table);
                splitPanel.removeComponent(reservationPanel);
            }
        });
        deleteButton.addClickListener(new Button.ClickListener() {

            @Override
            public void buttonClick(Button.ClickEvent event) {
                Reservation reservation = (Reservation) reservationBeanFieldGroup.getItemDataSource().getBean();
                List<Reservation> reservations = table.reserve(reservation);
                for (Reservation r : reservations) {
                    currentRoom.getReservations().remove(r);
                    reservationService.delete(r);
                }
            }
        });

        reservationPanel.setContent(form);

        splitPanel.setSecondComponent(reservationPanel);
    }

    private void initSearchPanel() {
        searchPanel = new Panel("Search");

        final DateField dateField = new DateField("Date: ");
        dateField.setDateFormat("yyyy-MM-dd");
        dateField.setImmediate(true);
        dateField.addValueChangeListener(new Property.ValueChangeListener() {

            @Override
            public void valueChange(Property.ValueChangeEvent event) {
                filterService.dateChanged(dateField.getValue());
                updateRoomLayout(filterService.filter(currentRole));
            }
        });
        dateField.setValue(new Date());

        final ComboBox hourComboBox = new ComboBox("Hour: ", hourList);
        hourComboBox.setNullSelectionAllowed(true);
        hourComboBox.setImmediate(true);
        hourComboBox.addValueChangeListener(new Property.ValueChangeListener() {

            @Override
            public void valueChange(Property.ValueChangeEvent event) {
                filterService.hourChanged((Integer) hourComboBox.getValue());
                updateRoomLayout(filterService.filter(currentRole));
            }
        });

        final ComboBox roleComboBox = new ComboBox("Use as: ", roleList);
//        roleComboBox.setNullSelectionAllowed(true);
        roleComboBox.setImmediate(true);
        roleComboBox.setValue(roleList.get(0));
        roleComboBox.addValueChangeListener(new Property.ValueChangeListener() {

            @Override
            public void valueChange(Property.ValueChangeEvent event) {
                currentRole = (Role) roleComboBox.getValue();
            }
        });
        nameTextField = new TextField("Name: ");
        nameTextField.setImmediate(true);
        nameTextField.addBlurListener(new FieldEvents.BlurListener() {

            @Override
            public void blur(FieldEvents.BlurEvent event) {
                filterService.reserverNameChanged(nameTextField.getValue());
                updateRoomLayout(filterService.filter(currentRole));
            }
        });
        final ComboBox eventComboBox = new ComboBox("Event: ", eventList);
        eventComboBox.setImmediate(true);
        eventComboBox.setNullSelectionAllowed(true);
        eventComboBox.addValueChangeListener(new Property.ValueChangeListener() {

            @Override
            public void valueChange(Property.ValueChangeEvent event) {
                filterService.eventChanged((ReservationEvent) eventComboBox.getValue());
                updateRoomLayout(filterService.filter(currentRole));
            }
        });

        final VerticalLayout content = new VerticalLayout();

        final HorizontalLayout dateAndHourLayout = new HorizontalLayout(dateField, hourComboBox);
        dateAndHourLayout.setMargin(false);
        dateAndHourLayout.setSpacing(true);

        final HorizontalLayout adminOnlyLayout = new HorizontalLayout(roleComboBox, nameTextField, eventComboBox);
        adminOnlyLayout.setMargin(false);
        adminOnlyLayout.setSpacing(true);

        content.addComponent(dateAndHourLayout);
        if (Role.ADMIN.equals(currentUser.getRole())) {
            content.addComponent(adminOnlyLayout);
        }
        searchPanel.setContent(content);
    }
}
